package com.atguigu.tingshu.search.factory;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * ScheduleTaskThreadFactory 类用于管理和调度定时任务。
 * 业务逻辑总结：
 * 1. **单例模式**：该类使用单例模式，确保整个应用程序中只有一个 `ScheduleTaskThreadFactory` 实例。
 *    - 使用静态常量 `INSTANCE` 来保存唯一的实例，并通过私有构造器防止外部实例化。
 *    - 提供 `getInstance()` 方法来获取该唯一实例。
 * 2. **定时任务调度**：提供一个线程池 `scheduledExecutorService` 来执行延时任务。
 *    - 线程池配置为单线程，以确保任务按顺序执行。
 *    - `execute(Runnable r, Long ttl, TimeUnit timeUnit)` 方法用于调度延时任务，接收任务、延时时间和时间单位作为参数。
 * 3. **时间差计算**：提供 `diffTime(Long currentTime)` 方法来计算当前时间与七天后凌晨两点的时间差。
 *    - 该方法返回时间差的绝对值，单位为毫秒。
 */
public class ScheduleTaskThreadFactory {

    // 定义一个定时/延时功能的线程池对象
    // 使用单一线程来执行定时任务，确保任务按顺序执行
    ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);

    // 定义一个实例对象，使用静态常量 INSTANCE 来保存类的唯一实例
    private static final ScheduleTaskThreadFactory INSTANCE = new ScheduleTaskThreadFactory();

    // 私有构造器，防止外部通过构造函数创建实例
    private ScheduleTaskThreadFactory() {
        // 构造器体为空，因为没有需要初始化的额外属性或逻辑
    }

    /**
     * 获取ScheduleTaskThreadFactory的单实例。
     *
     * @return ScheduleTaskThreadFactory的实例
     */
    public static ScheduleTaskThreadFactory getInstance() {
        // 返回类的唯一实例
        return INSTANCE;
    }

    /**
     * 执行一个延时任务。
     *
     * @param r          要执行的任务
     * @param ttl        延时的时间
     * @param timeUnit   时间单位
     */
    public void execute(Runnable r, Long ttl, TimeUnit timeUnit) {
        // 使用线程池调度任务，指定延时时间和时间单位
        scheduledExecutorService.schedule(r, ttl, timeUnit);
    }

    /**
     * 计算当前时间与七天后凌晨两点的时间差。
     *
     * @param currentTime 当前时间的毫秒值
     * @return 时间差，单位为毫秒
     */
    public long diffTime(Long currentTime) {
        // 获取当前日期并加上7天
        LocalDate localDate = LocalDate.now().plusDays(7);
        // 创建一个 LocalDateTime 对象，表示七天后的凌晨2点
        LocalDateTime localDateTime = LocalDateTime.of(localDate, LocalTime.of(2, 0, 0));
        // 将 LocalDateTime 转换为带有时区信息的 Instant，并获取其毫秒值
        long endTime = localDateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
        // 计算当前时间与结束时间的时间差，并返回绝对值
        return Math.abs(currentTime - endTime);
    }
}

